package controller

import (
	"math"

	. "gddgame.cc/galaxy/common/dsl/game/ad"
	. "gddgame.cc/galaxy/common/dsl/game/attr"
	. "gddgame.cc/galaxy/common/dsl/game/badge"
	. "gddgame.cc/galaxy/common/dsl/game/reward"
	"gddgame.cc/galaxy/common/dsl/game/user"
	. "gddgame.cc/galaxy/common/dsl/web"
	"gddgame.cc/galaxy/project/star/star/model"
	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/orm"

	"gddgame.cc/galaxy/utils/def"
)

func InitUser(context def.Context, user *model.User) error {
	if err := AddItems(context, model.DefaultItems, user); err != nil {
		return SystemExceptionDetail("用户道具失败", err)
	}
	// 查找道具
	var items []model.UserItem
	if _, err := model.UserItemModel.Query().Where("=", "user_id", user.Id).Find(&items); err != nil {
		return SystemExceptionDetail("查找用户道具失败", err)
	}
	// 装备默认
	data := map[string]interface{}{}
	useItems := []int{}
	itemIndex := 0
	for index := range items {
		userItem := items[index]
		item := Center.Items[userItem.ItemId]
		switch item.Type {
		case model.WeaponItem:
			data["weapon"] = userItem.Id
		case model.MachineItem:
			data["machine"] = userItem.Id
		case model.UseItem:
			if itemIndex >= model.MaxUserItemSet {
				continue
			}
			useItems = append(useItems, userItem.Id)
			itemIndex += 1
		}
	}
	if _, err := model.UserModel.PK(user.Id).Update(data); err != nil {
		return SystemExceptionDetail("装备道具失败", err)
	}
	return nil
}

func GetUserPublicInfo(context def.Context, user *model.User, language string) (*model.GameOtherUser, error) {
	// 账号信息，等级信息，属性信息
	data := &model.GameOtherUser{
		Entity: user.Entity,
		Score:  user.Score,
	}

	tmp := &model.GameUser{}
	if err := settingUserItem(context, user, tmp, language); err != nil {
		return nil, err
	}
	if err := settingUserAttr(context, user, tmp); err != nil {
		return nil, err
	}
	data.Items = tmp.Items
	data.Machine = tmp.Machine
	data.Weapon = tmp.Weapon
	data.StatRadar = tmp.StatRadar
	data.BadgeAttr = tmp.BadgeAttr
	data.BaseAttr = tmp.BaseAttr
	data.ItemAttr = tmp.ItemAttr
	return data, nil
}

func GetUserDetailInfo(context def.Context, user *model.User, language string) (*model.GameUser, error) {
	// 账号信息，等级信息，装备信息，道具信息，属性值
	data := &model.GameUser{
		Entity:  user.Entity,
		Score:   user.Score,
		Gold:    user.Gold,
		Diamond: user.Diamond,
	}

	if err := settingUserBadge(context, user, data); err != nil {
		return nil, err
	}
	if err := settingUserItem(context, user, data, language); err != nil {
		return nil, err
	}
	if err := settingUserAttr(context, user, data); err != nil {
		return nil, err
	}

	data.Gifts = make([]GiftNumber, len(model.GiftList))
	for index, v := range model.GiftList {
		number := 0
		if value, ok := user.Gifts[string(v)]; ok {
			number = value
		}
		data.Gifts[index] = GiftNumber{
			Key:    string(v),
			Number: number,
		}
	}

	return data, nil
}

func settingUserBadge(context def.Context, user *model.User, data *model.GameUser) error {
	data.Badges = make([]*UserBadge, 0, len(user.Badges))
	if err := Center.GetUserStats(context, user, Center.StatData); err != nil {
		return err
	}
	data.Badges = Center.FullBadge(user.Badges, user.StatInfo, data.Badges)
	return nil
}

func settingUserItem(context def.Context, user *model.User, data *model.GameUser, language string) error {
	var items []model.UserItem
	if err := Center.GetUserItems(user, append(user.Items, user.Weapon, user.Machine), &items); err != nil {
		return err
	}
	Items := Center.GetItem()
	itemMap := make(map[int]int, len(user.Items))
	for key, value := range user.Items {
		itemMap[value] = key
	}
	data.Items = make([]*model.UserItemExt, model.MaxUserItemSet)
	for _, item := range items {
		tmp := Items[item.ItemId]
		if user.Weapon == item.Id {
			data.Weapon = model.NewUserItem(&item, tmp)
		} else if user.Machine == item.Id {
			data.Machine = model.NewUserItem(&item, tmp)
		} else {
			index := itemMap[item.Id]
			data.Items[index] = model.NewUserItem(&item, tmp)
		}
	}
	return nil
}

func settingUserAttr(context def.Context, user *model.User, data *model.GameUser) error {
	if err := Center.GetUserStats(context, user, Center.StatData); err != nil {
		return err
	}
	baseAttr := AttrEffectSlice{}
	//baseAttr = baseAttr.MergeBase(model.LevelObjectAttrs[user.Level-1])
	itemAttr := AttrEffectSlice{}
	if data.Weapon != nil {
		itemAttr = itemAttr.Merge(data.Weapon.Item.Attr)
	}
	if data.Machine != nil {
		itemAttr = itemAttr.Merge(data.Machine.Item.Attr)
	}

	// 道具属性
	for _, item := range data.Items {
		if item == nil {
			continue
		}
		itemAttr = itemAttr.Merge(item.Item.Attr)
	}
	data.BaseAttr = baseAttr
	data.ItemAttr = itemAttr
	data.BadgeAttr, _ = Center.BadgeAttrMerge(user.Badges)

	list := make([]float32, len(model.StatRadarList))
	sum := 0
	max := 0
	min := -1
	for index, key := range model.StatRadarList {
		value := int(user.AllStats[key])
		list[index] = float32(value)
		sum += value
		if value > max {
			max = value
		}
		if value < min || min < 0 {
			min = value
		}
	}
	// 所有项的平均值+最大值最小值的平均值，指向2.5计算step
	step := float64(sum/len(model.StatRadarList)+(max+min)/2) / 2 / 50
	for index := range list {
		list[index] = float32(math.Min(1, float64(list[index])/step/100))
	}
	data.StatRadar = list
	return nil
}

func SwitchWeapon(context def.Context, user *model.User, userItemId int) error {
	if user.Weapon == userItemId {
		return nil
	}
	return Env.BatchClean([]string{"user/item/" + utils.ToString(user.Id), "user/" + utils.ToString(user.Id)}, func() error {
		if userItemId > 0 {
			var item model.UserItem
			if ok, err := model.UserItemModel.Query().Where("=", "user_id", user.Id).Where("=", "id", userItemId).One(&item); !ok {
				return SystemExceptionDetail("查找用户道具失败", err)
			}
			tmp := Center.Items[item.ItemId]
			if tmp.Type != model.WeaponItem {
				return ValidException("ITEM_TYPE_ERROR")
			}
		}

		user.Weapon = userItemId
		if _, err := model.UserModel.PK(user.Id).Update(map[string]interface{}{
			"weapon": user.Weapon,
		}); err != nil {
			return SystemExceptionDetail("切换武器失败", err)
		}
		return nil
	}, true)
}
func SwitchMachine(context def.Context, user *model.User, userItemId int) error {
	if user.Machine == userItemId {
		return nil
	}
	return Env.BatchClean([]string{"user/item/" + utils.ToString(user.Id), "user/" + utils.ToString(user.Id)}, func() error {
		if userItemId > 0 {
			var item model.UserItem
			if ok, err := model.UserItemModel.Query().Where("=", "user_id", user.Id).Where("=", "id", userItemId).One(&item); !ok {
				return SystemExceptionDetail("查找用户道具失败", err)
			}
			tmp := Center.Items[item.ItemId]
			if tmp.Type != model.MachineItem {
				return ValidException("ITEM_TYPE_ERROR")
			}
		}

		user.Machine = userItemId
		if _, err := model.UserModel.PK(user.Id).Update(map[string]interface{}{
			"machine": user.Machine,
		}); err != nil {
			return SystemExceptionDetail("切换装甲失败", err)
		}
		return nil
	}, true)
}
func SwitchItem(context def.Context, user *model.User, userItemId int, offset int) error {
	if len(user.Items) > offset && user.Items[offset] == userItemId {
		return nil
	}
	return Env.BatchClean([]string{"user/item/" + utils.ToString(user.Id), "user/" + utils.ToString(user.Id)}, func() error {
		if userItemId > 0 {
			var item model.UserItem
			if ok, err := model.UserItemModel.Query().Where("=", "user_id", user.Id).Where("=", "id", userItemId).One(&item); !ok {
				return SystemExceptionDetail("查找用户道具失败", err)
			}
			tmp := Center.Items[item.ItemId]
			if tmp.Type != model.UseItem {
				return ValidException("ITEM_TYPE_ERROR")
			}
		}

		// 填充item列表
		if len(user.Items)-1 < offset {
			t := make([]int, offset+1)
			for key := range user.Items {
				t[key] = user.Items[key]
			}
			user.Items = t
		}
		// 判断是否需要交换道具位置
		if userItemId > 0 && user.Items[offset] != userItemId {
			tmp := user.Items[offset]
			for index, key := range user.Items {
				if key == userItemId {
					// 交换2个位置
					user.Items[index] = tmp
				}
			}
		}

		user.Items[offset] = userItemId
		if _, err := model.UserModel.PK(user.Id).Update(map[string]interface{}{
			"items": user.Items,
		}); err != nil {
			return SystemExceptionDetail("切换道具失败", err)
		}
		return nil
	}, true)
}

func ReceiveReward(context def.Context, user *model.User, reward *Reward, data map[string]interface{}) error {
	items := reward.GetItems()
	if err := VerifyItems(context, items, user.Id); err != nil {
		return err
	}
	if data == nil {
		data = make(map[string]interface{})
	}
	if reward.Gold > 0 {
		data["gold"] = &orm.UpdateOperate{Operate: "+", Value: reward.Gold}

		if err := user.ChangeStats(context, model.GoldStat, int32(reward.Gold), false); err != nil {
			return err
		}
		if err := UpdateBadgeSingle(context, user, model.GoldBadge, data); err != nil {
			return err
		}
	}
	if reward.Diamond > 0 {
		data["diamond"] = &orm.UpdateOperate{Operate: "+", Value: reward.Diamond}
	}
	if len(reward.Gifts) > 0 {
		if user.Gifts == nil {
			user.Gifts = make(map[string]int, len(reward.Gifts))
		}
		for _, gn := range reward.Gifts {
			if _, ok := user.Gifts[gn.Key]; !ok {
				user.Gifts[gn.Key] = 0
			}
			user.Gifts[gn.Key] += gn.Number
		}
		data["gifts"] = user.Gifts
	}

	if err := AddItems(context, items, user); err != nil {
		return err
	}
	return nil
}

func UpdateBadgeSingle(context def.Context, user *model.User, badgeId int, data map[string]interface{}) error {
	if badgeId == 0 {
		return nil
	}
	if user.Badges == nil {
		user.Badges = make(map[int]*UserBadge)
	}
	if ok, err := Center.ValidBadge(user.Badges, user.StatInfo, user.OpenId, badgeId); err != nil {
		return err
	} else if !ok {
		return nil
	}
	if err := Center.ChangeBadge(user.Badges, data); err != nil {
		return err
	}
	return nil
}

func GetGift(context def.Context, user *model.User, giftKey string, number int, language string) (*Reward, error) {
	gift := GiftType(giftKey)
	logic := model.GiftLogicMap[gift]
	g, ok := user.Gifts[giftKey]
	if !ok {
		if gift == model.GiftAd {
			t, err := NextAdTime(Env, user.OpenId, model.GiftAdPlane)
			if err != nil {
				return nil, err
			}
			if !t.Ok() {
				return nil, ValidException("AD_WAIT")
			}
			if err := UpdateAdTime(Env, user.OpenId, t); err != nil {
				return nil, err
			}
		} else {
			return nil, ValidException("GIFT_EMPTY")
		}
		// 用户积分:
		// todo 最高积分
		logic = GenerateLogic(Env, user.Score*100/model.UserScoreBase, Center.MaxItemLevel, RewardGold|RewardItem)
		logic.AddItems(Center.ItemMap)
	} else {
		if g < number {
			return nil, ValidException("GIFT_NUMBER_ERROR")
		} else if g > number {
			user.Gifts[giftKey] -= number
		} else {
			delete(user.Gifts, giftKey)
		}
	}
	reward := Reward{}
	for i := 0; i < number; i++ {
		GenerateReward(Env, logic, &reward, Center.ItemMap)
	}
	data := map[string]interface{}{}
	data["gifts"] = user.Gifts

	if err := Center.GetUserStats(context, user, Center.StatData); err != nil {
		return nil, err
	}
	if err := ReceiveReward(context, user, &reward, data); err != nil {
		return nil, err
	}
	if err := user.ChangeStats(context, model.GiftStat, int32(number), false); err != nil {
		return nil, err
	}
	if err := UpdateBadgeSingle(context, user, model.GiftBadge, data); err != nil {
		return nil, err
	}
	if err := Center.UpdateUser(user, data); err != nil {
		return nil, err
	}
	reward.BindInfo(Center.GetItem(), language)
	return &reward, nil
}

func SendShareMessage(context def.Context, userId int, target string, nickName string) (*user.UserMessage, error) {
	message := &user.UserMessage{
		UserId:   userId,
		Type:     model.ShareMessage,
		TargetId: target,
		Status:   false,
		Content: map[string]string{
			"nick_name": nickName,
		},
		Reward: model.DefaultShareReward,
	}
	if err := Center.SendMessage(message); err != nil {
		return nil, err
	}
	return message, nil
}
